/**
	Pulsar engine. Core.
	Frame allocation memory

	Copyright (C) 2013-2014 Dmitry Dolgov

	This program is free software; you can redistribute it and/or modify it under the terms of the
	GNU General Public License as published by the Free Software Foundation; either version 2 of
	the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
	without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
	See the GNU General Public License for more details.
*/

#define __PL_NO_MEMORY_MAPPING__

#include <pulsar/pulsar.h>
#include <pulsar/src/pulsar_intr.h>

namespace pl
{

static pl_int32 _frameSize = 0;          // Frame allocation size
static void* _frameMemoryPointer = NULL; // Pointer to frame allocation storage
static pl_int32 _currentFrameOffset;     // Current frame allocation storage
static pl::CriticalSection* _csFrame = NULL;

} // namespace pl

/**
	Set frame allocation size
*/
void pl::StartupFuncBase::setFrameAllocSize(pl_int32 size)
{
	_frameSize = size;
	return;
}

/*
	Initialize frame memory
*/
void pl::initMemoryFrame()
{
	_currentFrameOffset = 0;
	if (_frameSize > 0)
	{
		_csFrame = PL_NEW pl::CriticalSection;
		_frameMemoryPointer = malloc(_frameSize);
	}
	return;
}

/*
	Shutdown frame memory
*/
void pl::termMemoryFrame()
{
	if (_frameMemoryPointer != NULL)
	{
		_frameSize = 0;
		discardFrame();

		free(_frameMemoryPointer);
		_frameMemoryPointer = NULL;

		PL_DELETE _csFrame;
		_csFrame = NULL;
	}
	return;
}

/**
	Allocate storage from frame memory
*/
void* pl::allocFrame(pl_int32 size, int align)
{
	if (_csFrame == NULL || _frameMemoryPointer == NULL)
	{
		PL_MEM_ERROR2(NULL, size, MEMORY_ERROR_OUT);
		return NULL;
	}

	pl::Lock l(_csFrame);

	pl_int32 currentOffset = _currentFrameOffset;

	if (align > 0 && ((currentOffset % align) != 0))
	{
		align = (align - (currentOffset % align));
		currentOffset += align;
	}

	if (currentOffset + size > _frameSize)
	{
		PL_MEM_ERROR2(NULL, size, MEMORY_ERROR_OUT);
		return NULL;
	}

	pl_uint8* p = (pl_uint8*)(_frameMemoryPointer) + currentOffset;
	_currentFrameOffset = currentOffset + size;
	return (void*)p;
}

/**
	Removes all frame allocations
*/
void pl::discardFrame()
{
	if (_csFrame != NULL)
	{
		pl::Lock l(_csFrame);
		_currentFrameOffset = 0;
	}
	return;
}

//
// End of file 'pulsar_memoryframe.cpp'
//
